package programs;

import game.Ship;

import java.util.*;

import be.kuleuven.cs.som.annotate.Basic;
import programs.expression.implementedClasses.Variable;
import programs.expression.superClasses.ExpressionType;
import programs.statement.Action;
import programs.statement.BasicStatement;
import programs.statement.Statement;

public class Program {
	
	private final Map<String,Variable> globalVariables = new HashMap<String,Variable>();
	private final Statement mainStatement;
	private Iterator<BasicStatement> mainIterator;
	private Ship executer = null;
		
	public Program(Map<String, ExpressionType> globals, Statement mainStatement, boolean constuctor) {
		this.mainStatement = mainStatement;
		assignGlobalVariables(globals);
	}

	@Basic
	public Map<String,Variable> getGlobalVariables(){
		return globalVariables;
	}
	
	public int getNbGlobalVariables() {
		return getGlobalVariables().size();
	}

	public boolean variablesAreDeclared(){
		Set<Variable> set = getMainStatement().getVariables();
		for(Variable var: set) {
			if( !getGlobalVariables().containsValue(var) )
				return false;
		}
		return true;
	}
	
	@Basic
	public Variable getGlobalVariable(String name) {
		return getGlobalVariables().get(name);
	}
	
	@Basic
	public Statement getMainStatement() {
		return mainStatement;
	}
	
	@Basic
	public Ship getExecuter() {
		return this.executer;
	}
	
	public void setExecuter(Ship executer) {
		this.executer = executer;
		getMainStatement().setExecuter(executer);
		this.mainIterator = mainStatement.getIterator();
	}

	public void executeUntilNextAction() {
		boolean actionExecuted = false;
		while(getMainIterator().hasNext() && ! actionExecuted ) {
			BasicStatement next = getMainIterator().next();
			if(!next.isValidStatement())
				return;
			next.execute();
			if(next instanceof Action)
				actionExecuted = true;
		}
	}
	
	public void reset() {
		this.mainIterator = getMainStatement().getIterator();
	}
	
	public void assignGlobalVariables(Map<String,ExpressionType> globals) {
		for(String name : globals.keySet()) {
			Variable global = new Variable(name, globals.get(name));
			mainStatement.assignGlobalVariable(global);
			getGlobalVariables().put(name,global);
		}
	}
	
	public boolean isTypeCorrect() {
		return getMainStatement().isValidStatement() && variablesAreDeclared();
	}

	public Iterator<BasicStatement> getMainIterator() {
		return mainIterator;
	}

}
